# Get the command and optional parameters from the command line arguments
param (
    [Parameter(Position = 0, Mandatory = $false)]
    [string]$Command,

    [Parameter(Position = 1, Mandatory = $false)]
    [string]$ProjectSlug,

    [Alias("e")]
    [string]$Environment = "",

    [Alias("k")]
    [string]$VariableKey = "",

    [Alias("v")]
    [string]$VariableValue = "",

    [switch]$ExportToFile
)

# Function to display help
function Show-Help {
    Write-Output @"
Usage: .\GitLabCICD.ps1 <command> <project-slug> [options]

Commands:
  GetVariables           Get the CI/CD variables for the specified project.
  AddOrUpdateVariable    Add or update a CI/CD variable for the specified project.

Options:
  <project-slug>             The slug of the project. (required for all commands)
  -e, -Environment <string>  The environment scope to filter variables or apply to the variable. (optional)
  -ExportToFile              Export the output to a file. (optional, applicable for GetVariables command only)
  -k, -VariableKey <string>  The key of the variable to add or update. (required for AddOrUpdateVariable command)
  -v, -VariableValue <string> The value of the variable to add or update. (required for AddOrUpdateVariable command)

Environment Variables:
  GITLAB_HOST          The base URL of the GitLab instance (e.g., https://gitlab.example.com).
  GITLAB_TOKEN         The personal access token for accessing the GitLab API.
"@
}

# Show help if no arguments are provided
if (-not $Command -and -not $ProjectSlug) {
    Show-Help
    exit 0
}

# Check if the ProjectSlug parameter is provided for the relevant commands
if ($Command -and (-not $ProjectSlug)) {
    Write-Error "The parameter 'project-slug' is required for the command '$Command'."
    exit 1
}

# Define variables (only if not showing help)
if ($Command -ne "Help") {
    $gitlabHost = $env:GITLAB_HOST
    $gitlabApiUrl = "$gitlabHost/api/v4"
    $privateToken = $env:GITLAB_TOKEN

    if (-not $gitlabHost) {
        Write-Error "GitLab host is not set in environment variable 'GITLAB_HOST'"
        exit 1
    }

    if (-not $privateToken) {
        Write-Error "API token is not set in environment variable 'GITLAB_TOKEN'"
        exit 1
    }
}

# Function to get project ID by slug
function Get-ProjectID {
    param (
        [string]$projectSlug
    )

    # Set the API endpoint for project search
    $url = "$gitlabApiUrl/projects?search=$projectSlug"

    # Set headers for the request
    $headers = @{
        "PRIVATE-TOKEN" = $privateToken
    }

    # Get project info from GitLab API
    $response = Invoke-RestMethod -Uri $url -Headers $headers -Method Get

    # Find the exact project match by slug
    $project = $response | Where-Object { $_.path -eq $projectSlug }

    if ($project) {
        return $project.id
    } else {
        Write-Error "Project with slug '$projectSlug' not found."
        exit 1
    }
}

# Function to get CI/CD variables
function Get-CICDVariables {
    param (
        [string]$projectId,
        [string]$environment = ""
    )

    # Set the API endpoint
    $url = "$gitlabApiUrl/projects/$projectId/variables"

    # Set headers for the request
    $headers = @{
        "PRIVATE-TOKEN" = $privateToken
    }

    # Get variables from GitLab API
    $response = Invoke-RestMethod -Uri $url -Headers $headers -Method Get

    # Filter variables by environment if specified
    if ($environment) {
        $filteredResponse = $response | Where-Object { $_.environment_scope -eq $environment }
    } else {
        $filteredResponse = $response
    }

    return $filteredResponse
}

# Function to add or update a CI/CD variable
function Add-Or-Update-Variable {
    param (
        [string]$projectId,
        [string]$variableKey,
        [string]$variableValue,
        [string]$environment = ""
    )

    # Set the API endpoint for the variables
    $url = "$gitlabApiUrl/projects/$projectId/variables"

    # Set headers for the request
    $headers = @{
        "PRIVATE-TOKEN" = $privateToken
    }

    # Prepare the request data
    $data = @{
        key = $variableKey
        value = $variableValue
        environment_scope = $environment
    }

    # Check if the variable with the same key and environment already exists
    $existingVariables = Invoke-RestMethod -Uri $url -Headers $headers -Method Get
    $existingVariable = $existingVariables | Where-Object { $_.key -eq $variableKey -and $_.environment_scope -eq $environment }

    # If the variable exists, update it; otherwise, create it
    if ($existingVariable) {
        $variableId = $existingVariable.id
        $updateUrl = "$url/$variableId"
        Invoke-RestMethod -Uri $updateUrl -Headers $headers -Method Put -ContentType "application/json" -Body ($data | ConvertTo-Json -Compress)
        Write-Output "Variable '$variableKey' updated successfully."
    } else {
        Invoke-RestMethod -Uri $url -Headers $headers -Method Post -ContentType "application/json" -Body ($data | ConvertTo-Json -Compress)
        Write-Output "Variable '$variableKey' added successfully."
    }
}

# Execute the specified command
switch ($Command) {
    "GetVariables" {
        # Get the project ID
        $projectId = Get-ProjectID -projectSlug $ProjectSlug

        # Get the variables
        $variables = Get-CICDVariables -projectId $projectId -environment $Environment

        # Create a custom object for each variable to display in table format and sort them
        $variableObjects = $variables | ForEach-Object {
            [PSCustomObject]@{
                KEY   = $_.key
                ENV   = $_.environment_scope
                VALUE = $_.value
            }
        } | Sort-Object ENV, KEY

        # Display the variables in a table format
        $variableObjects | Format-Table -Property KEY, ENV, VALUE -AutoSize

        # Export the variables to a text file if ExportToFile parameter is provided
        if ($ExportToFile) {
            # Create timestamp
            $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"

            # Create output file name
            $outputFile = if ($Environment) {
                "$ProjectSlug-$Environment-variables-$timestamp.txt"
            } else {
                "$ProjectSlug-variables-$timestamp.txt"
            }

            $variableObjects | Format-Table -Property KEY, ENV, VALUE -AutoSize | Out-File -FilePath $outputFile
            Write-Output "Variables have been saved to $outputFile"
        }
    }

    "AddOrUpdateVariable" {
        # Get the project ID
        $projectId = Get-ProjectID -projectSlug $ProjectSlug

        if (-not $VariableKey -or -not $VariableValue) {
            Write-Error "The parameters '-k' (VariableKey) and '-v' (VariableValue) are required for adding or updating a variable."
            exit 1
        }
        Add-Or-Update-Variable -projectId $projectId -variableKey $VariableKey -variableValue $VariableValue -environment $Environment
    }
    default {
        Show-Help
        exit 0
    }
}
